package com.zhu.rpc.client;

import com.zhu.rpc.JsonUtil;
import com.zhu.rpc.MsgType;
import com.zhu.rpc.RpcProtocol;
import com.zhu.rpc.exception.RemoteCallException;
import com.zhu.rpc.msgBean.RpcRequestBean;
import com.zhu.rpc.msgBean.RpcResponseBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RpcMsgCallBack<T> {
    private RpcRequestBean rpcRequest;
    private RpcResponseBean rpcResponse;
    private Lock lock = new ReentrantLock();
    private Condition finish = lock.newCondition();
    private long timeout = 1*1000;
    //重发次数
    private int resendTimes= 3;
    private long time;
    private String asyncClass;
    private String methodName;
    private Logger logger = LoggerFactory.getLogger(getClass());
    public RpcMsgCallBack(RpcRequestBean rpcRequest,String methodName){
        this.rpcRequest = rpcRequest;
        this.methodName = methodName;
    }
    public void setAsyncClass(Method m) {
        //获取实际类型
        if (m.getGenericReturnType() instanceof ParameterizedTypeImpl){
            Type type = ((ParameterizedTypeImpl)m.getGenericReturnType()).getActualTypeArguments()[0];
            this.asyncClass = type.getTypeName();
        }else {
            this.asyncClass = "java.lang.Object";
        }
    }

    public Object getResult(){
        try {
            lock.lock();
            time = System.currentTimeMillis();
            await();
            logger.debug("调用时间："+(System.currentTimeMillis()-time));
            if (rpcResponse.isErr()){
                //远程调用异常
                logger.error("调用远程服务出现异常，msgId：{} error{}",rpcRequest.getMsgId(),rpcResponse.getErrMsg());
                throw new RemoteCallException(rpcResponse.getErrMsg());
            }
            return asyncClass ==null?rpcResponse.getResult():
                    RpcProtocol.getParamObj(Class.forName(asyncClass),String.valueOf(rpcResponse.getResult()));
        }catch (Exception e){

        }finally {
            lock.unlock();
        }
        return null;
    }

    private void await(){
        boolean unTimeout = false;
        try {
            unTimeout = finish.await(timeout, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (!unTimeout){
            //消息重发
            if (--resendTimes >= 0){
                logger.error("消息:{}接收 正在重试发送消息 还剩{}次 发送机会",rpcRequest.getMsgId(),resendTimes);
                RpcRequest.sendRpcRequestMsg(methodName, new StringBuilder(JsonUtil.toJson(rpcRequest)), MsgType.callReReq);
                await();
            }else {
                logger.error("消息：{}发送失败达到顶峰 已放弃此消息",rpcRequest.getMsgId());
                throw new RemoteCallException("远程服务器未返回数据");
            }
        }
    }

    //通知结果
    public void notifyResult(RpcResponseBean response){
        try {
            lock.lock();
            this.rpcResponse = response;
            finish.signal();
        }finally {
            lock.unlock();
        }

    }

}
